//*************************************************************************************
// EGTB Generator Compression Verification
//*************************************************************************************


#pragma once

#include "CompressionVerification.h"

// Database Reader Template Definiton Macro
#define DBREADER CDbReader<MaxPieces, MaxPieces, MaxRank>

// templated versions of functions
namespace EndGameDB
{

	// Verifies compression of one database slice
	//////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxField, int BitsPerRow, int MaxPieces, int MaxRank, typename DB_READER>
	bool VerifyCompression(int wm, int wk, int bm, int bk, int wmrank, int bmrank, FILE* fLog, DB_READER* pReader)
	{
		// prepare cycle
		int64 size = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		int64 index;

		// report progress
		if(OnVerifyCompressSubDbStartedPtr != NULL)
			OnVerifyCompressSubDbStartedPtr(wm, wk, bm, bk, wmrank, bmrank);

	
		// for both color sides
		for(int color = 0; color < 2; color++)
		{
			// iterate through all BitBoards
			for(index = 0; index < size; index++)
			{
				// get BitBoard
				BB p;
				IndexToBitBoardXX<BB>(index, &p, wm, wk, bm, bk, wmrank, bmrank);

				// check impossible BitBoard
				if(p.bm & p.wm)
					continue;

				// test if capture, we ignore captures, they are not searched in the engine
				// if capture BitBoard, continue
				if(TestJump<BB>(g_ED, &p, color == WHITE))
					continue;

				// get BitBoard from compressed database
				uint8 cprDTM;
				int cprValue = pReader->Lookup<BB, BitsPerRow, MaxField>(&p, color, &cprDTM);

				// get BitBoard from uncompressed database
				uint8 uncprDTM;
				// DEBUG - complete
				int uncprValue = Lookup<BB, MaxField, BitsPerRow, false>(&p, color, &uncprDTM);

				if(cprValue != UNKNOWN)
				{

					// check, if they are the same
					if(cprValue != uncprValue)
					{
						fprintf(fLog, "[%d,%d,%d,%d](%d,%d): Cpr: %d, Uncpr: %d\n", wm, wk, bm, bk, wmrank, bmrank, cprValue, uncprValue);
						errorCount++;
					}

					if(cprValue == WIN || cprValue == LOSS)
					{
						if(cprDTM != uncprDTM)
						{
							fprintf(fLog, "[%d,%d,%d,%d](%d,%d): CprDTM: %d, UncprDTM: %d\n", wm, wk, bm, bk, wmrank, bmrank, cprDTM, uncprDTM);
							errorCount++;
						}			
					}
				}

			} // for
		} // for

		return true;
	}


	// Verifies compression of one sub-database 
	//////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxRank, int MaxField, int BitsPerRow, int MaxPieces, typename DB_READER>
	int VerifySubDb(int wm,int wk,int bm,int bk, FILE* fLog, DB_READER* pReader)
	{
		int wmrank, bmrank; // maximal rank of the white and black men
		int n = bm+bk+wm+wk;

		// is this a valid database?
		// one side has no pieces:
		if((bm+bk==0) || (wm+wk==0)) return 0;


		// white has more pieces than black
		if(wm+wk<bm+bk)
			return 0;

		// absurd databases: if maxpieces = 8, we don't do 5-3, 6-2, 7-1 or 6-1 or 5-1 etc.
		// this depends on MAXPIECE of course!
		if(wm+wk>MAXPIECE)
			return 0;

		// more bk than wk in case of equal number of pieces
		if(wk+wm==bk+bm)
		{
			if(bk>wk)
				return 0;
		}

		if(bm==0 && wm==0)
			VerifyCompression<BB, MaxField, BitsPerRow, MaxPieces, MaxRank, DB_READER>(wm,wk,bm,bk,0,0, fLog, pReader);
	
		if(wm!=0 && bm==0)
		{
			for(wmrank=MaxRank-1;wmrank>=((wm-1)/BitsPerRow);wmrank--)
				VerifyCompression<BB, MaxField, BitsPerRow, MaxPieces, MaxRank, DB_READER>(wm,wk,bm,bk,wmrank,0, fLog, pReader);
		}
	
		if(bm!=0 && wm==0)
		{
			for(bmrank=MaxRank-1;bmrank>=((bm-1)/BitsPerRow);bmrank--)
				VerifyCompression<BB, MaxField, BitsPerRow, MaxPieces, MaxRank, DB_READER>(wm,wk,bm,bk,0,bmrank, fLog, pReader);
		}

		if(wm!=0 && bm!=0)
		{
			for(wmrank=MaxRank-1;wmrank>=((wm-1)/BitsPerRow);wmrank--)
			{
				for(bmrank=MaxRank-1;bmrank>=((bm-1)/BitsPerRow);bmrank--)
					VerifyCompression<BB, MaxField, BitsPerRow, MaxPieces, MaxRank, DB_READER>(wm,wk,bm,bk,wmrank,bmrank, fLog, pReader);
			}
		}

		return 1;
	}

	// Verifies compression of one database file
	//////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxRank, int MaxField, int BitsPerRow, int MaxPieces, typename DB_READER>
	int VerifyDb(int n, FILE* fLog, DB_READER* pReader)
	{

		int bm=0,bk=0,wm=0,wk=0;
		int div1, div2, div3;

		for(div1=0;div1<=n;div1++)
		{
			for(div2=div1;div2<=n;div2++)
			{
				for(div3=div2;div3<=n;div3++)
				{
					wm=div1;
					wk=div2-div1;
					bm=div3-div2;
					bk=n-div3;
					VerifySubDb<BB, MaxRank, MaxField, BitsPerRow, MaxPieces, DB_READER>(wm,wk,bm,bk, fLog, pReader);
				}
			}
		}

		return 1;
	}


	// Compression Verification main API function
	//////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxRank, int MaxField, int BitsPerRow, int MaxPieces>
	void VerifyDatabaseCompression(eCheckersType checkersType, const wchar_t* lpDir)
	{
		// TO-DO: refactor the logging file name
		FILE* fLog = NULL;
		_wfopen_s(&fLog, L"c:\\Log\\RleVer_error.log", L"w");
		errorCount = 0;

		if(fLog)
		{
			// allocate the global movegen configuration
			g_ED = new SEngineData();
			memset(g_ED, 0, sizeof(SEngineData));

			// set bitboard generators
			SetCheckersTypeMoveGen(g_ED, checkersType);

			// create reader
			DBREADER* pReader = new CDbReader<MaxPieces, MaxPieces, MaxRank>();
			pReader->Initialize(200, g_ED, lpDir);

			// do verification itself
			for(int n=2; n<=MaxPieces; n++)
			{
				VerifyDb<BB, MaxRank, MaxField, BitsPerRow, MaxPieces, CDbReader<MaxPieces, MaxPieces, MaxRank> >(n, fLog, pReader);
			}

			// clean up
			delete pReader;
			pReader = NULL;

			delete g_ED;
			g_ED = NULL;
		} // if

		fprintf(fLog, "Error count: %d\n", errorCount);
		fclose(fLog);
	}
}